/*
 *所有关于productionbatchesview类的业务代码应在此处编写
*可使用repository.调用常用方法，获取EF/Dapper等信息
*如果需要事务请使用repository.DbContextBeginTransaction
*也可使用DBServerProvider.手动获取数据库相关信息
*用户信息、权限、角色等使用UserContext.Current操作
*productionbatchesviewService对增、删、改查、导入、导出、审核业务代码扩展参照ServiceFunFilter
*/
using VolPro.Core.BaseProvider;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
using System.Linq;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
using VolPro.Core.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using SMes.DbMethod.IRepositories;
using VolPro.Core.ManageUser;
using System.Net;
using SMes.DbMethod.ViewModel;
using VolPro.Core.DBManager;
using System.Threading.Tasks;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SMes.DbMethod.Http;
using Newtonsoft.Json;
using System;

namespace SMes.DbMethod.Services
{
    public partial class productionbatchesviewService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IproductionbatchesviewRepository _repository;//访问数据库
        private readonly SendMesDataToPlc dataToPlc;

        [ActivatorUtilitiesConstructor]
        public productionbatchesviewService(
            IproductionbatchesviewRepository dbRepository,
            IHttpContextAccessor httpContextAccessor,
            SendMesDataToPlc sendMesDataToPlc
            )
        : base(dbRepository)
        {
            dataToPlc = sendMesDataToPlc;
            _httpContextAccessor = httpContextAccessor;
            _repository = dbRepository;
            //多租户会用到这init代码，其他情况可以不用
            //base.Init(dbRepository);
        }

        public override WebResponseContent Add(SaveModel saveDataModel)
        {
            WebResponseContent webResponse = new();
            var productionbatchesview = saveDataModel.MainData.DicToEntity<productionbatchesview>();
            var planNo = DateTime.Now.ToString("yyMMdd");
            var OldOrder = _repository.DbContext.Set<productionorders>().AsNoTracking()
                .FirstOrDefault(x => x.PlanNo == planNo);
            if (OldOrder != null)
            {
                productionbatches productionbatches = new()
                {
                    BatchCode = productionbatchesview.BatchCode,
                    ProductID = productionbatchesview.ProductID,
                    StartPartNum = productionbatchesview.StartPartNum,
                    Quantity = productionbatchesview.Quantity,
                    OrderID = OldOrder.OrderID,//订单ID来源于生产订单表
                    Status = productionbatchesview.Status,
                    StartDate = productionbatchesview.StartDate,
                    Operators = UserContext.Current.UserTrueName,
                    Memo = productionbatchesview.Memo
                };
                //生产批次表
                _repository.DbContext.Set<productionbatches>().Add(productionbatches);
            }
            else
            {
                productionorders productionorders = new()
                {
                    PlanNo = planNo,
                    OrderDate = DateTime.Now,
                    Status = 1,
                    Priority = 10,
                    Memo = "正常订单"
                };
                //生产批次表
                productionbatches productionbatches = new()
                {
                    BatchCode = productionbatchesview.BatchCode,
                    ProductID = productionbatchesview.ProductID,
                    StartPartNum = productionbatchesview.StartPartNum,
                    Quantity = productionbatchesview.Quantity,
                    Status = productionbatchesview.Status,
                    StartDate = productionbatchesview.StartDate,
                    Operators = UserContext.Current.UserTrueName,
                    Memo = productionbatchesview.Memo,
                    AreaName="默认区域"
                };
                productionorders.productionbatches.Add(productionbatches);
                //生产订单表
                _repository.DbContext.Set<productionorders>().Add(productionorders);
                //没有对应的生产订单
                // return webResponse.Error("当前日期没有对应的生产订单，请先创建生产订单");
            }
            _repository.DbContext.SaveChanges();
            return webResponse.OK("创建生产任务成功....");
        }
        public override WebResponseContent Update(SaveModel saveDataModel)
        {
            WebResponseContent webResponse = new();
            var updateItem = saveDataModel.MainData.DicToEntity<productionbatchesview>();
            var oldBatches = _repository.DbContext.Set<productionbatches>().FirstOrDefault(m=>m.BatchID==updateItem.BatchID&& m.Status == 0);
            if(oldBatches == null)
            {
                return webResponse.Error($"当前批次{updateItem.BatchCode}不存在，请重新选择....");
            }
            oldBatches.Operators = UserContext.Current.UserTrueName;
            oldBatches.EndDate = DateTime.Now;
            oldBatches.Status = 0;
            oldBatches.OldBatchCode =updateItem.BatchCode;
            oldBatches.BatchCode =updateItem.BatchCode;
            oldBatches.ProductID = updateItem.ProductID;
            oldBatches.StartPartNum = updateItem.StartPartNum;
            oldBatches.Quantity = updateItem.Quantity;
            oldBatches.Memo = updateItem.Memo;
            _repository.DbContext.Set<productionbatches>().Update(oldBatches);
            _repository.DbContext.SaveChanges();
            return webResponse.OK("更新生产任务成功....");
        }
        public override WebResponseContent Del(object[] keys, bool delList = true)
        {
            WebResponseContent webResponse = new();
            //将keys转换为表的主键类型一致，用于下面的查询
            var ids = keys.Select(s => s.GetInt()).ToList();
            if (ids == null || ids.Count < 1) return webResponse.Error("主键不符合规定....");

            try
            {
                var productionbatches = _repository.DbContext.Set<productionbatches>().Where(m => ids.Contains(m.BatchID)&&m.Status==0);
                if (productionbatches == null || productionbatches.Count() < 1)
                {
                    return webResponse.Error($"未找到生产任务主键相关的表数据{string.Join(" ", ids)}....");
                }
                _repository.DbContext.Set<productionbatches>().RemoveRange(productionbatches);
                _repository.DbContext.SaveChanges();
                return webResponse.OK("删除生产任务成功....");
            }
            catch (Exception ex)
            {
                return webResponse.Error("删除生产任务成功ex:" + ex.Message);
            }
          
        }
        /// <summary>
        /// 作废批次号
        /// </summary>
        /// <param name="removeWorkBatchViewModel"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> SetWorkBathStatusRemove(RemoveWorkBatchViewModel removeWorkBatchViewModel)
        {
            WebResponseContent webResponse = new();
            var productionbatches =await _repository.DbContext.Set<productionbatches>().FindAsync(removeWorkBatchViewModel.BatchID);
            if(productionbatches == null|| productionbatches.Status!=2)
            {
                return webResponse.Error($"当前批次{removeWorkBatchViewModel.BatchCode}不存在或状态不正确，请重新操作....");
            }
            ///暂时拼接字符按照批次号-1进行
            //List<string> batchCodes = [];
            var maxValue =Convert.ToInt32(productionbatches.Quantity) +(int)(productionbatches.StartPartNum ?? 1);
            var min = maxValue-removeWorkBatchViewModel.Quantity;
            //for (int i= min; i < maxValue; i++)
            //{
            //    batchCodes.Add($"{productionbatches.BatchCode}-{i}");
            //}
           // var pprecords_Mains=_repository.DbContext.Set<pprecords_main>().Where(m=>m.Status == 0 && batchCodes.Contains(m.LotNo)).ToList();
            productionbatches.Operators = UserContext.Current.UserTrueName;
            productionbatches.EndDate = DateTime.Now;
            productionbatches.Status = -1;
            productionbatches.OldBatchCode = removeWorkBatchViewModel.BatchCode;
            productionbatches.Memo = removeWorkBatchViewModel.Memo+$"作废的数量[{removeWorkBatchViewModel.Quantity}]";
            productionbatches.RemoveQuantity = removeWorkBatchViewModel.Quantity;
            _repository.DbContext.Set<productionbatches>().Update(productionbatches);
            if(min > 0)
            {
               await _repository.DbContext.Set<pprecords_main_copy>()
                    .Where(m=>m.IndexNum> min&&m.BatchID== productionbatches.BatchID).ExecuteDeleteAsync();
            }
            _repository.DbContext.SaveChanges();
            return webResponse.OK($"作废批次号{productionbatches.BatchCode}成功的数量{removeWorkBatchViewModel.Quantity}....");
        }

        public async Task<WebResponseContent> SetWorkBathStatus(WorkBatchViewModel workBatchViewModel)
        {
            WebResponseContent webResponse = new();
            var productionbatches = await _repository.DbContext
                .Set<productionbatches>().Include(m=>m.Productionorders).Include(m => m.GetProducts)
                .FirstOrDefaultAsync(m=>m.BatchID==workBatchViewModel.BatchID);
            if (productionbatches == null) return webResponse.Error($"当前批次{workBatchViewModel.BatchID}不存在，请重新选择....");
            var processformulamain = await _repository.DbContext
                .Set<processformulamain>().AsNoTracking()
                .FirstOrDefaultAsync(m => m.ProductId == productionbatches.ProductID);
            int formulaTagValue = 0;
            if (processformulamain != null)
            {
                formulaTagValue =Convert.ToInt32(processformulamain.FormulaTag);
            }
            //判断当前批次号是否已经开工
            //开工。。。。。
            if (workBatchViewModel.Status == 1)
            {
                if (productionbatches.Status == 0|| productionbatches.Status==2)
                {
                    var item = Convert.ToInt32(productionbatches.Quantity);
                    var maxValue = item +(int)(productionbatches.StartPartNum ?? 1);
                    using (var transaction = repository.DbContext.Database.BeginTransaction())
                    {
                        try
                        {
                            //写入PLC
                            var res = await WriteValueToPlc(productionbatches.BatchCode, productionbatches.StartPartNum ?? 1, item, formulaTagValue);

                            if (!res) return webResponse.Error($"批次号{productionbatches.BatchCode}写入PLC失败....");
                            if (productionbatches.Status == 0)
                            {
                                List<pprecords_main_copy> pprecords_Mains = new();
                                for (int i = productionbatches.StartPartNum ?? 1; i < maxValue; i++)
                                {
                                    var batchCode = $"{productionbatches.BatchCode}-{i}";
                                    pprecords_Mains.Add(new pprecords_main_copy()
                                    {
                                        LotID = Guid.NewGuid().ToString(),
                                        LotNo = batchCode,
                                        ProductCode = productionbatches.GetProducts.ProductCode,
                                        CreateTime = DateTime.Now,
                                        PlanNo = productionbatches.Productionorders.PlanNo,
                                        Status = 0,
                                        BatchNo = productionbatches.BatchCode,
                                        IndexNum = i,
                                        BatchID = productionbatches.BatchID,
                                    });
                                }
                                if (maxValue > 6000)
                                {
                                    DBServerProvider.GetSqlDapper<pprecords_main_copy>().BulkInsert(pprecords_Mains, "pprecords_main_copy");
                                }
                                else
                                {
                                  await  _repository.DbContext.Set<pprecords_main_copy>().AddRangeAsync(pprecords_Mains);
                                }                               
                            }
                            await _repository.DbContext.Set<productionbatches>().Where(m => m.BatchID != workBatchViewModel.BatchID && m.Status == 1)
                            .ExecuteUpdateAsync(m => m.SetProperty(x => x.Status, 2)
                            .SetProperty(x => x.Operators, UserContext.Current.UserTrueName)
                            .SetProperty(x => x.EndDate, DateTime.Now));
                            //将当前批次号的状态改为1
                            //下发任务至MES设备
                            productionbatches.Operators = UserContext.Current.UserTrueName;
                            productionbatches.EndDate = DateTime.Now;
                            productionbatches.Status = 1;
                            
                            _repository.DbContext.Set<productionbatches>().Update(productionbatches);
                            _repository.DbContext.SaveChanges();
                            transaction.Commit();
                            return webResponse.OK($"批次号{productionbatches.BatchCode}开工成功....");
                          
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message + ex.StackTrace);
                            transaction.Rollback();
                            return webResponse.Error($"批次号{productionbatches.BatchCode}开工失败....");
                        }
                    }
                    
                }
                return webResponse.Error($"批次号{productionbatches.BatchCode}已经开工，不能重复操作....");  
            }
            //暂停。。。。。。
            if (workBatchViewModel.Status == 2)
            {
                if(productionbatches.Status == 1)
                {

                    productionbatches.Operators = UserContext.Current.UserTrueName;
                    productionbatches.EndDate = DateTime.Now;
                    productionbatches.Status = 2;
                    _repository.DbContext.Set<productionbatches>().Update(productionbatches);
                    _repository.DbContext.SaveChanges();
                    return webResponse.OK($"批次号{productionbatches.BatchCode}暂停作业成功....");
                }
                return webResponse.Error($"批次号{productionbatches.BatchCode}未运行，不能进行暂停作业....");

            }
            return webResponse.Error($"当前批次{workBatchViewModel.BatchID}不不符合要求，请重新选择....");
        }
        /// <summary>
        ///写入设备参数组的方法
        /// </summary>
        /// <param name="lotNo">批次条码</param>
        /// <param name="start">开始编码</param>
        /// <param name="Amount">总数量</param>
        /// <param name="groupNum">配方组号</param>
        public async Task<bool> WriteValueToPlc(string lotNo,int start,int Amount,int groupNum)
        {
            try
            {
               var equipmenttagaddresses =
                await _repository.DbContext.Set<equipmenttagaddress>()
                .Where(m => m.Property == "WriteParamsToplc" && m.Tag < 10).AsNoTracking().ToListAsync();
            List<DriverAddressModel> driverAddressModels = [];
            foreach (var item in equipmenttagaddresses)
            {
                if (item.Tag < 1 || item.Tag > 5) continue;
                driverAddressModels.Add(new DriverAddressModel
                {
                    TagName = item.Name,
                    Address = item.PlcAddress,
                    Value = item.Tag == 1 ? lotNo
                             : item.Tag == 2 ? start
                             : item.Tag == 3 ? Amount
                             : item.Tag == 4 ? groupNum :
                             1,
                    ValueType = (VariableTypeEnum)item.DataType
                });
            }
                var result = await dataToPlc.SendManydatasToPlc(driverAddressModels) ??
                        throw new Exception("转换数据失败");
                var driverReponse = JsonConvert.DeserializeObject<DriverReponse>(result)??
                     throw new Exception("转换数据失败"); ;
                return driverReponse.IsSuccess;
            }
            catch(Exception ex)
            {
                Console.WriteLine("wtire plc data ex:" + ex);
                return false;
            }
        }
    }
}
